package com.fz.us.admin.base.service.impl;

import com.fz.us.admin.base.bean.BaseEnumManager;
import com.fz.us.admin.base.bean.search.Search;
import com.fz.us.admin.base.bean.search.rule.Rule;
import com.fz.us.admin.base.bean.search.rule.RuleHelper;
import com.fz.us.admin.base.entity.parent.NameEntity;
import com.fz.us.admin.base.service.BaseService;
import com.fz.us.admin.base.service.common.ResultService;
import com.fz.us.admin.base.utils.EntityUtil;
import com.fz.us.admin.base.bean.search.result.*;
import com.fz.us.admin.base.bean.Result;
import com.fz.us.admin.base.bean.search.SearchEnum;
import com.fz.us.admin.base.bean.search.order.Order;
import com.fz.us.admin.base.bean.search.page.PageHelp;
import com.fz.us.admin.base.bean.search.page.PagePaging;

import com.fz.us.admin.base.dao.BaseDao;
import com.fz.us.admin.base.entity.BaseEntity;
import com.fz.us.admin.base.utils.PinyinUtil;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Service实现类 - Service实现类基类
 * ============================================================================
 * 版权所有 2016 。
 *
 * @author fallenpanda
 * @version 1.0 2016-07-19 。
 * ============================================================================
 */
@Service
public abstract class BaseServiceImpl<T extends BaseEntity, PK extends Serializable> implements BaseService<T, PK> {

    public abstract BaseDao<T, PK> getBaseDao();

    @Resource
    protected ResultService resultService;

    public Object getObject(String className, PK id) {
        return getBaseDao().getObject(className, id);
    }

    public T get(PK id) {
        return getBaseDao().get(id);
    }

    public T load(PK id) {
        return getBaseDao().load(id);
    }

    public List<T> get(PK[] ids) {
        return getBaseDao().get(ids);
    }

    public T get(String propertyName, Object value) {
        return getBaseDao().get(propertyName, value);
    }

    public boolean isUnique(String propertyName, Object oldValue, Object newValue) {
        return getBaseDao().isUnique(propertyName, oldValue, newValue);
    }

    public boolean isExist(String propertyName, Object value) {
        return getBaseDao().isExist(propertyName, value);
    }

    public List<T> getList(String propertyName, Object value) {
        return getBaseDao().getList(propertyName, value);
    }

    public List<T> getAll() {
        return getBaseDao().getAll();
    }

    public Long getTotalCount() {
        return getBaseDao().getTotalCount();
    }

    public PK save(T entity) {
        if (entity instanceof NameEntity) {
            if (((NameEntity) entity).getState() == null) ((NameEntity) entity).setState(BaseEnumManager.StateEnum.Enable);
            if (StringUtils.isNotEmpty(((NameEntity) entity).getName())) {
                ((NameEntity)entity).setPinYin(PinyinUtil.getPingYin(((NameEntity)entity).getName()));
                ((NameEntity)entity).setPinYinHead(PinyinUtil.getPinYinHeadChar(((NameEntity)entity).getName()));
            }
        }
        return getBaseDao().save(entity);
    }

    public Result saveEntity(T entity) {
        try {
            if(save(entity) == null){
                return resultService.fail("保存失败！");
            }
        } catch (DataIntegrityViolationException e) {
            return resultService.fail("请勿重复提交！");
        }
        return resultService.successWithId(entity.getId());
    }

    public void update(T entity) {
        if (entity instanceof NameEntity) {
            if (StringUtils.isNotEmpty(((NameEntity) entity).getName())) {
                ((NameEntity)entity).setPinYin(PinyinUtil.getPingYin(((NameEntity)entity).getName()));
                ((NameEntity)entity).setPinYinHead(PinyinUtil.getPinYinHeadChar(((NameEntity)entity).getName()));
            }
        }
        getBaseDao().update(entity);
    }

    @Override
    public Result methodEntity(BaseEnumManager.MethodEnum method, PK id) {
        Assert.notNull(method, "method is required");
        Assert.notNull(id, "id is required");

        T entity = get(id);
        if (entity != null) {
            Assert.isTrue(entity instanceof NameEntity, "entity must extends NameEntity");

            if (entity instanceof NameEntity) {
                if (BaseEnumManager.MethodEnum.Delete.equals(method)) {// 删除
                    ((NameEntity) entity).setState(BaseEnumManager.StateEnum.Delete);
                    update(entity);

                    return resultService.successWithId(entity.getId());
                } else if (BaseEnumManager.MethodEnum.Enable.equals(method)) {// 启用
                    ((NameEntity) entity).setState(BaseEnumManager.StateEnum.Enable);
                    update(entity);

                    return resultService.successWithId(entity.getId());
                } else if (BaseEnumManager.MethodEnum.Disenable.equals(method)) {// 禁用
                    ((NameEntity) entity).setState(BaseEnumManager.StateEnum.Disenable);
                    update(entity);

                    return resultService.successWithId(entity.getId());
                }
            }

        }

        return resultService.fail();
    }

    public void delete(T entity) {
        getBaseDao().delete(entity);
    }

    public void delete(PK id) {
        getBaseDao().delete(id);
    }

    public void delete(PK[] ids) {
        getBaseDao().delete(ids);
    }

    public void flush() {
        getBaseDao().flush();
    }

    public void clear() {
        getBaseDao().clear();
    }

    public void evict(Object object) {
        getBaseDao().evict(object);
    }

    public Query createQuery(String hql) {
        return getBaseDao().createQuery(hql);
    }

    public SQLQuery createSqlQuery(String sql) {
        return getBaseDao().createSqlQuery(sql);
    }

    public Object getUniqueResult(String hql) {
        return getBaseDao().getUniqueResult(hql);
    }

    public List<T> getList(String hql) {
        return getBaseDao().getList(hql);
    }

    public Object getUniqueResult(String hql, Map<String, Object> params) {
        return getBaseDao().getUniqueResult(hql, params);
    }

    public List<T> getList(String hql, Map<String, Object> params) {
        return getBaseDao().getList(hql, params);
    }

    public List<Object[]> getObjectsList(String hql, Map<String, Object> params) {
        return getBaseDao().getObjectsList(hql, params);
    }

    public List<Map<String, Object>> getMapList(String hql, Map<String, Object> params) {
        return getBaseDao().getMapList(hql, params);
    }

    public SearchResult findBySearch(Search search) {
        return getBaseDao().findBySearch(search);
    }

    public SearchResultCount findCountBySearch(List<Rule> rules) {
        return (SearchResultCount) findBySearch(Search.newBuilder()
                .setPage(PageHelp.rowCount())
                .addRules(rules)
                .build());
    }

    public SearchResultUnique findUniqueBySearch(List<Rule> rules) {
        return (SearchResultUnique) findBySearch(Search.newBuilder()
                .setPage(PageHelp.uniqueResult())
                .addRules(rules)
                .build());
    }

    public SearchResultList findListBySearch(List<Rule> rules, Order... orders) {
        if (orders == null || orders.length == 0) orders = new Order[]{Order.simpleOrder()};
        return (SearchResultList) findBySearch(Search.newBuilder()
                .setPage(PageHelp.list())
                .addRules(rules)
                .addOrders(orders)
                .build());
    }

    public SearchResultPaging findPagingBySearch(PagePaging page, List<Rule> rules, Order... orders) {
        if (page == null) page = PagePaging.page(0,0);
        if (orders == null || orders.length == 0) orders = new Order[]{Order.simpleOrder()};
        return (SearchResultPaging) findBySearch(Search.newBuilder()
                .setPage(page)
                .addRules(rules)
                .addOrders(orders)
                .build());
    }

    @Override
    public List<T> getList(Map<String, Object> params) {
        PagePaging page = PagePaging.page(0,0);
        List<Rule> rules = Lists.newArrayList();
        if(params != null && params.size()>0){
            for(Map.Entry<String,Object> entry:params.entrySet()) {
                if(entry.getValue().getClass().isArray()){
                    rules.add( RuleHelper.in(entry.getKey(),(Object[]) entry.getValue()));
                }else{
                    rules.add(RuleHelper.eq(entry.getKey(), entry.getValue()));
                }
            }
        }
        // 默认排序
        Order  order = Order.order("createTime", SearchEnum.OrderType.asc);
        List<Order> orders =  new ArrayList<Order>();
        orders.add(order);
        SearchResultPaging searchResultPaging  =  (SearchResultPaging) findBySearch(Search.newBuilder()
                .setPage(page)
                .addRules(rules)
                .addOrders(orders)
                .build());
        return searchResultPaging.getList();
    }

    @Override
    public SearchResultPaging findPagingBySearch(PagePaging page, List<Rule> rules,Map<String, Object> params, Order... orders) {
        if (page == null) page = PagePaging.page(0,0);
        if (orders == null || orders.length == 0) orders = new Order[]{Order.simpleOrder()};
        if(params != null && params.size()>0){
           for(Map.Entry<String,Object> entry:params.entrySet()) {
               if(entry.getValue().getClass().isArray()){
                   rules.add( RuleHelper.in(entry.getKey(),(Object[]) entry.getValue()));
               }else{
                   rules.add(RuleHelper.eq(entry.getKey(), entry.getValue()));
               }
           }
        }
        return (SearchResultPaging) findBySearch(Search.newBuilder()
                .setPage(page)
                .addRules(rules)
                .addOrders(orders)
                .build());
    }
    @Override
    public Object getObjectEntity(String keyId, String className) {
        return getBaseDao().getObjectEntity(keyId, className);
    }



    @Override
    public boolean calStepCon(String formulaField, String formulaFlag, String formulaVal, String keyId, String entityName) {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine se = manager.getEngineByName("js");
        String className = entityName.substring(entityName.lastIndexOf(".") + 1);
        Object object = this.getObjectEntity(keyId, className);
        boolean result = false;
        if(object != null) {
            Object obj = EntityUtil.getFieldValueByName(formulaField, object);
            String formula = "";
            String str = "";
            if(StringUtils.equals("==", formulaFlag) || StringUtils.equals("!=", formulaFlag)){
                formula = formulaField + formulaFlag + "\""+ formulaVal + "\"" ;
                str = "var "+formulaField+"=\"" +obj+ "\";"+formula;
            }else{
                formula = formulaField + formulaFlag + formulaVal ;
                str = "var "+formulaField+"="+obj+ ";"+formula;
            }
            try {
                result =  Boolean.parseBoolean(se.eval(str).toString());
            } catch (ScriptException e) {
                e.printStackTrace();
            }
        }
        return  result;
    }
}